<template>
  <mxp-bubble
    ref="mxpBubbleRef"
    :buttonText="option.buttonText"
    :buttonTextSize="option.buttonTextSize"
    :buttonTextColor="option.buttonTextColor"
    :buttonTextStyle="option.buttonTextStyle"
    :bubbleStyle="option.bubbleStyle"
    :background="option.background"
    :width="width"
    :height="height"
    :direction="option.direction"
    :zIndex="option.zIndex"
    :mask="option.mask"
    :cusStyle="option.cusStyle"
    :cusClass="option.cusClass"
    :maskClose="option.maskClose"
    @animationEnd="onAnimationEnd"
    @show="onShow"
    @hide="onHide"
    @animationStart="onAnimationStart"
  >
    <template #button>
      <!-- 按钮 -->
      <slot></slot>
    </template>
    <template #default>
      <!-- 菜单 -->
      <view class="menu-list" :style="[option.menuStyle, menuStyle]">
        <template v-for="(item, index) in list" :key="index">
          <mxp-line v-if="option.menuItemBorderColor && index !== 0" :color="option.menuItemBorderColor"></mxp-line>
          <view
            class="menu-item"
            :class="[item.disabled || item.loading ? 'hover-class' : '', option.cusClass]"
            :hoverClass="!item.disabled && !item.loading ? 'hover-class' : ''"
            :hoverStartTime="0"
            :hoverStayTime="0"
            :style="[option.menuItemStyle, item.menuItemStyle || {}]"
            @click="onClick(index, item)"
          >
            <mxp-icon
              v-if="item.loading"
              name="jiazai"
              :spin="true"
              :color="option.menuItemColor"
              :size="option.menuItemIconSize || option.menuItemFontSize"
            ></mxp-icon>
            <mxp-icon-image
              v-else-if="item.icon"
              :icon="item.icon"
              :size="option.menuItemIconSize || option.menuItemFontSize"
              :cusStyle="{ marginRight: '10px' }"
            ></mxp-icon-image>
            <text class="menu-item-text" :style="{ fontSize: option.menuItemFontSize, color: option.menuItemColor }">{{ item.label }}</text>
            <mxp-badge v-if="item.badge" :badge="item.badge" v-bind="{ ...option.badgeOption, ...item.badgeOption }"></mxp-badge>
          </view>
        </template>
      </view>
    </template>
  </mxp-bubble>
</template>

<script lang="ts" setup>
  import { type CSSProperties, ref } from 'vue';
  import type { $AllColorStr, $SizeUnitStr } from '@/mxp-ui/mxp-tool/types/interface';
  import MxpIconImage from '../mxp-icon-image/mxp-icon-image.vue';
  import MxpLine from '../mxp-line/mxp-line.vue';
  import MxpIcon from '../mxp-icon/mxp-icon.vue';
  import MxpBubble from '@/mxp-ui/mxp-bubble/mxp-bubble.vue';
  import MxpBadge, { type $BadgeProps } from '../mxp-badge/mxp-badge.vue';
  import { removeObjectEmpty } from '../mxp-tool/utils/obj';

  export type $BubbleMenuItem = {
    [x: string]: unknown;
    /** 标题名称 */
    label: string;
    /** 图片路径 */
    icon?: string;
    /** 是否加载中 */
    loading?: boolean;
    /** 是否禁用 */
    disabled?: boolean;
    /** 角标 */
    badge?: number | string;
    /** 角标配置 */
    badgeOption?: $BadgeProps;
    /** 每个 菜单 的样式 */
    menuItemStyle?: CSSProperties;
  };
  export type $BubbleMenuProps = {
    /** 菜单数组 [{  icon:'', tltle: '全部', badge: 99 }] */
    menuList?: ($BubbleMenuItem | number | string)[]; // eslint-disable-line vue/no-unused-properties
    /** 弹出提示框的宽度 */
    width?: $SizeUnitStr;
    /** 弹出提示框的高度 */
    height?: $SizeUnitStr;
    /** 整个菜单的样式 */
    menuStyle?: CSSProperties;
    /** 每项菜单的样式 */
    menuItemStyle?: CSSProperties; // eslint-disable-line vue/no-unused-properties
    /** 每项菜单底部的边框  */
    menuItemBorderColor?: $AllColorStr | boolean | 'transparent'; // eslint-disable-line vue/no-unused-properties
    /** 菜单文字颜色 */
    menuItemColor?: $AllColorStr; // eslint-disable-line vue/no-unused-properties
    /** 菜单文字大小 */
    menuItemFontSize?: $SizeUnitStr; // eslint-disable-line vue/no-unused-properties
    /** 菜单颜色 */
    menuItemIconSize?: $SizeUnitStr; // eslint-disable-line vue/no-unused-properties
    /** 需要显示的提示文字 */
    buttonText?: number | string; // eslint-disable-line vue/no-unused-properties
    /** 按钮文本大小 */
    buttonTextSize?: $SizeUnitStr; // eslint-disable-line vue/no-unused-properties
    /** 按钮文本颜色 */
    buttonTextColor?: $AllColorStr; // eslint-disable-line vue/no-unused-properties
    /** 按钮文本颜色 */
    buttonTextStyle?: CSSProperties; // eslint-disable-line vue/no-unused-properties
    /** 角标配置 */
    badgeOption?: $BadgeProps; // eslint-disable-line vue/no-unused-properties
    /** 弹出内容的样式 */
    bubbleStyle?: CSSProperties; // eslint-disable-line vue/no-unused-properties
    /** 弹出提示框时，文本的背景色 */
    background?: $AllColorStr; // eslint-disable-line vue/no-unused-properties
    /** 弹出提示的方向， 'auto' | 'bottom' | 'left' | 'right' | 'top' */
    direction?: 'auto' | 'bottom' | 'left' | 'right' | 'top'; // eslint-disable-line vue/no-unused-properties
    /** 弹出提示的z-index，nvue无效 */
    zIndex?: number; // eslint-disable-line vue/no-unused-properties
    /** 点击列表的某一项是否自动关闭 */
    selectClose?: boolean; // eslint-disable-line vue/no-unused-properties
    /** 是否显示透明遮罩以防止触摸穿透 */
    mask?: boolean; // eslint-disable-line vue/no-unused-properties
    /** 是否可以点击遮罩关闭 */
    maskClose?: boolean; // eslint-disable-line vue/no-unused-properties
    /** 自定义的样式属性 */
    cusStyle?: CSSProperties; // eslint-disable-line vue/no-unused-properties
    /** 自定义类名 */
    cusClass?: string; // eslint-disable-line vue/no-unused-properties
  };
  export type $BubbleMenuOption = $BubbleMenuProps & {
    /** 显示 */
    show?: () => void;
    /** 隐藏 */
    hide?: (type: 'mask' | 'rest' | 'select') => void;
    /** 选择某一项 */
    select?: (index: number) => void;
    /** 动画开始 */
    animationStart?: (type: 'hide-animation' | 'show-animation') => void;
    /** 动画完成 */
    animationEnd?: (type: 'hide-animation' | 'show-animation') => void;
  };

  defineOptions({
    name: 'mxp-bubble-menu',
  });
  const props = withDefaults(defineProps<$BubbleMenuProps>(), {
    menuList: () => [],
    menuStyle: () => ({}),
    menuItemStyle: () => ({}),
    width: undefined,
    height: undefined,
    menuItemBorderColor: false,
    menuItemFontSize: '16px',
    menuItemColor: '#333333',
    menuItemIconSize: '18px',
    buttonText: '',
    buttonTextSize: '14px',
    buttonTextColor: '#606266',
    buttonTextStyle: () => ({}),
    badgeOption: () => ({}),
    bubbleStyle: () => ({ padding: '0 15px' }),
    background: '#ffffff',
    direction: 'auto',
    zIndex: 888,
    selectClose: true,
    mask: true,
    maskClose: true,
    cusStyle: () => ({}),
    cusClass: '',
  });
  defineSlots<{
    /** 主体内容 */
    default?: () => void;
  }>();
  const emits = defineEmits<{
    /** 显示 */
    (e: 'show'): void;
    /** 隐藏 */
    (e: 'hide', type: 'mask' | 'rest' | 'select'): void;
    /** 选择某一项 */
    (e: 'select', index: number, item: any): void;
    /** 动画开始 */
    (e: 'animationStart', type: 'hide-animation' | 'show-animation'): void;
    /** 动画完成 */
    (e: 'animationEnd', type: 'hide-animation' | 'show-animation'): void;
  }>();

  const list = ref<$BubbleMenuItem[]>([]);
  const option = ref<$BubbleMenuOption>({});
  const mxpBubbleRef = ref<InstanceType<typeof MxpBubble> | null>(null);
  /** 监听显示 */
  function onShow() {
    if (!('menuList' in option.value) || !Array.isArray(option.value.menuList)) {
      option.value = { ...props };
    }
    list.value = option.value.menuList!.map((item) => {
      if (typeof item === 'number' || typeof item === 'string') {
        return { label: item, badge: '' } as $BubbleMenuItem;
      } else {
        return item;
      }
    });
    emits('show');
    typeof option.value.show === 'function' && option.value.show();
  }
  /** 监听隐藏 */
  function onHide(type: 'mask' | 'rest') {
    if (type !== 'rest') {
      emits('hide', type);
      typeof option.value.hide === 'function' && option.value.hide(type);
    }
  }

  /** 关闭完成 */
  function onAnimationEnd(type: 'hide-animation' | 'show-animation') {
    emits('animationEnd', type);
    typeof option.value.animationEnd === 'function' && option.value.animationEnd(type);
  }
  /** 开始动画 */
  function onAnimationStart(type: 'hide-animation' | 'show-animation') {
    emits('animationStart', type);
    typeof option.value.animationStart === 'function' && option.value.animationStart(type);
  }
  /** 点击事件 */
  function onClick(index: number, item: $BubbleMenuItem) {
    if (!item.disabled || !item.loading) {
      emits('select', index, item);
      typeof option.value.select === 'function' && option.value.select(index);
    }
    if (!item.loading && option.value!.selectClose) {
      hide('select');
      typeof option.value.hide === 'function' && option.value.hide('select');
    }
  }

  /**
   * 关闭
   */
  function hide(type: 'select') {
    mxpBubbleRef.value?.hide();
    emits('hide', type);
    typeof option.value.hide === 'function' && option.value.hide(type);
  }
  defineExpose({
    /**
     * 显示
     * 支持手动给定 按钮 位置信息 从而无需 <slot #button></slot> 适合用于一个页面有多个bubble，的情况
     */
    show(rect?: UniApp.NodeInfo, param: $BubbleMenuOption = {}) {
      option.value = { ...props, ...removeObjectEmpty(param) };
      mxpBubbleRef.value?.show(rect);
    },
    /** 隐藏 */
    hide,
  });
</script>

<style lang="scss" scoped>
  .menu-list {
    display: flex;
    flex-flow: column nowrap;
    align-items: stretch;
    justify-content: flex-start;

    .menu-item {
      display: flex;
      flex: 1;
      flex-flow: row nowrap;
      align-items: center;
      justify-content: flex-start;

      &.hover-class {
        opacity: 0.7;
      }

      .menu-item-text {
        display: flex;
        flex: 1;
        flex-flow: row nowrap;
        padding: 10px 0;
        font-size: 16px;
        color: #333333;
      }
    }
  }
</style>
